﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
using Sausage.Common;
using Sausage.Web.Code;
using Sausage.Web.DataModel;
using Sausage.Web.Models;
using Telerik.Web.Mvc;

namespace Sausage.Web.Domain
{
    public class ProjectLabourHelper
    {
        public static GridModel<object> Select(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID); 

            using (var context = new SausageEntities())
            {
                return
                    QueryProjectLabour(
                        context.ProjectLabour.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)ProjectDataStateEnum.Confirmed)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> SubmitSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
            {
                return
                    QueryProjectLabour(
                        context.ProjectLabour.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)ProjectDataStateEnum.Unsubmit ||
                             item.State == (int)ProjectDataStateEnum.AuditRejected)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> AuditSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
            {
                return
                    QueryProjectLabour(context.ProjectLabour.Where(item =>
                    organization.Contains(item.OrganizationID) &&
                    (item.State == (int)ProjectDataStateEnum.Submitted ||
                     item.State == (int)ProjectDataStateEnum.SignRejected))
                    , query, isWithChild);
            }
        }

        public static GridModel<object> SignSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
            {
                return
                    QueryProjectLabour(context.ProjectLabour.Where(item =>
                    organization.Contains(item.OrganizationID) &&
                    (item.State == (int)ProjectDataStateEnum.Audited ||
                     item.State == (int)ProjectDataStateEnum.ConfirmationRejected))
                    , query, isWithChild);
            }
        }

        public static GridModel<object> ConfirmSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            
            using (var context = new SausageEntities())
            {
                return
                    QueryProjectLabour(context.ProjectLabour.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)ProjectDataStateEnum.Signed)
                    , query, isWithChild);
            }
        }

        private static GridModel<object> QueryProjectLabour(IQueryable<ProjectLabour> source, JosnPagingQueryModel query, bool isWithChild)
        {
            var result = UIHelper.GetGridModelFromQueryModel<ProjectLabour>(
                source,
                query.page,
                query.limit,
                GetSortDescriptorFromQueryModel(query.SortModel),
                GetSearchFilterFromQueryModel(query.FilterModel, isWithChild));

            var list = result.Data.Select(item => new
                                                      {
                                                          item.LabourID,
                                                          item.QuantityID,
                                                          item.OrganizationID,
                                                          Organization = item.Organization.OrganizationName,
                                                          item.ProjectID,
                                                          ProjectCode = item.Project.ProjectCode,
                                                          ProjectName = item.Project.ProjectName,
                                                          ConstructionID = item.ProjectQuantity.ConstructionID,
                                                          Construction = item.ProjectQuantity.Construction.ConstructionName,
                                                          item.JobID,
                                                          Job = item.Job.ItemName,
                                                          item.LabourTypeID,
                                                          LabourType = item.LabourType.ItemName,
                                                          item.Quantity,
                                                          item.Price,
                                                          item.Amount,
                                                          item.CreateDate,
                                                          item.Applicant,
                                                          item.ApplicationDate,
                                                          item.Auditor,
                                                          item.AuditedDate,
                                                          item.Signer,
                                                          item.SignedDate,
                                                          item.Approver,
                                                          item.ApprovedDate,
                                                          item.State,
                                                          item.IsDelay,
                                                          item.Memo,
                                                          item.Comment
                                                      }).ToList();

            return new GridModel<object>()
            {
                Aggregates = result.Aggregates,
                Data = list,
                Total = result.Total
            };
        }

        private static List<IFilterDescriptor> GetSearchFilterFromQueryModel(IEnumerable<JosnQueryFilterModel> filterModels, bool isWithChild)
        {
            var filterList = new List<IFilterDescriptor>();
            foreach (var item in filterModels)
            {
                if (string.IsNullOrEmpty(item.value))
                    continue;
                
                if (item.property == "OrganizationID" && isWithChild)
                    continue; 
                
                if (item.property.EndsWith("ID", StringComparison.InvariantCultureIgnoreCase))
                {
                    var targetID = Guid.Parse(item.value);
                    if (targetID != Guid.Empty)
                        filterList.Add(new FilterDescriptor(item.property, FilterOperator.IsEqualTo, targetID));
                }
                else if (item.property == "ApplicationDate_L") //startData - begin
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "ApplicationDate_H") // startDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else if (item.property == "SignedDate_L") // signedDate - begin.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("SignedDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "SignedDate_H") // signedDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("SignedDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else //other filter.
                    filterList.Add(new FilterDescriptor(item.property, FilterOperator.Contains, item.value));
            }
            return filterList;
        }

        private static List<SortDescriptor> GetSortDescriptorFromQueryModel(IEnumerable<JosnQuerySortModel> sortModels)
        {
            //convert the sort description.
            var sortList = new List<SortDescriptor>();
            foreach (var item in sortModels)
            {
                var descriptor = new SortDescriptor()
                {
                    Member = item.property,
                    SortDirection =
                        item.direction.ToLower() == "desc"
                            ? ListSortDirection.Descending
                            : ListSortDirection.Ascending
                };

                if (descriptor.Member == "Organization")
                    descriptor.Member = "Organization.OrganizationName";
                else if (descriptor.Member == "ProjectName")
                    descriptor.Member = "Project.ProjectName";
                else if (descriptor.Member == "ProjectCode")
                    descriptor.Member = "Project.ProjectCode";
                else if (descriptor.Member == "Construction")
                    descriptor.Member = "ProjectQuantity.Construction.ConstructionName";
                else if (descriptor.Member == "LabourType")
                    descriptor.Member = "LabourType.ItemName";
                else if (descriptor.Member == "Job")
                    descriptor.Member = "Job.ItemName";

                sortList.Add(descriptor);
            }
            return sortList;
        }

        public static ProjectLabour GetProjectLabourByID(Guid id)
        {
            using (var context = new SausageEntities())
            {
                return context.ProjectLabour.Include("Organization").Include("Project").Include("ProjectQuantity").Include("Job").Include("LabourType").Include("ProjectQuantity.Construction").FirstOrDefault(item => item.LabourID == id);
            }
        }

        public static void DeleteProjectLabour(Guid id)
        {
            using (SausageEntities context = new SausageEntities())
            {
                var entity = context.ProjectLabour.FirstOrDefault(item => item.LabourID == id);
                if (null != entity)
                {
                    context.ProjectLabour.DeleteObject(entity);
                    context.SaveChanges();
                }
            }
        }

        public static void UpdateProjectLabour(ProjectLabourListRow data)
        {
            using (SausageEntities context = new SausageEntities())
            {
                var entity = context.ProjectLabour.FirstOrDefault(item => item.LabourID == data.LabourID);
                if (entity == null)
                    return;

                if (entity.State != (int)ProjectDataStateEnum.Unsubmit && entity.State != (int)ProjectDataStateEnum.AuditRejected)
                    throw new SausageException(string.Format("项目工程人工已经提交，不允许执行编辑操作。"));

                entity.QuantityID = data.QuantityID;
                entity.ProjectID = ProjectQuantityHelper.GetProjectQuantityByID(data.QuantityID).ProjectID;
                entity.JobID = data.JobID;
                entity.LabourTypeID = data.LabourTypeID;
                entity.Quantity = data.Quantity;
                entity.Price = data.Price;
                entity.Amount = data.Quantity * data.Price;
                entity.Applicant = Helper.CurrentPrincipal.User.UserName;
                //entity.ApplicationDate = data.ApplicationDate;
                entity.Memo = data.Memo;

                context.SaveChanges();
            }
        }

        public static void CreateProjectLabour(ProjectLabourListRow data)
        {
            using (SausageEntities context = new SausageEntities())
            {
                ProjectLabour entity = new ProjectLabour();
                entity.LabourID = Guid.NewGuid();
                entity.QuantityID = data.QuantityID;
                entity.OrganizationID = Helper.CurrentPrincipal.Organization.OrganizationID;
                entity.ProjectID = data.ProjectID;
                entity.JobID = data.JobID;
                entity.LabourTypeID = data.LabourTypeID;
                entity.Quantity = data.Quantity;
                entity.Price = data.Price;
                entity.Amount = data.Quantity * data.Price;
                entity.CreateDate = DateTime.Now;
                entity.Applicant = Helper.CurrentPrincipal.User.UserName;
                entity.ApplicationDate = data.ApplicationDate;
                entity.State = (int)ProjectDataStateEnum.Unsubmit;
                entity.IsDelay = Helper.IsDelay(data.ApplicationDate);
                entity.Memo = data.Memo;

                context.ProjectLabour.AddObject(entity);
                context.SaveChanges();
            }
        }

        public static void UpdateProjectLabourState(Guid id, int state)
        {
            using (SausageEntities context = new SausageEntities())
            {
                var target = context.ProjectLabour.FirstOrDefault(item => item.LabourID == id);
                if (null != target)
                {
                    target.State = state;
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteSubmit(Guid[] labours)
        {
            if (null != labours && labours.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectLabour.Where(item => labours.Contains(item.LabourID)).ToList();

                    foreach (var entity in list)
                    {
                        entity.State = (int)ProjectDataStateEnum.Submitted;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteAudit(Guid[] labours, bool passed, string comment)
        {
            if (null != labours && labours.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectLabour.Where(item => labours.Contains(item.LabourID)).ToList();

                    foreach (var target in list)
                    {
                        target.Auditor = Helper.CurrentPrincipal.User.UserName;
                        target.AuditedDate = DateTime.Now;
                        target.Comment = comment;
                        target.State = passed
                                                     ? (int)ProjectDataStateEnum.Audited
                                                     : (int)ProjectDataStateEnum.AuditRejected;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteConfirm(Guid[] labours, bool passed, string comment)
        {
            if (null != labours && labours.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectLabour.Where(item => labours.Contains(item.LabourID)).ToList();

                    foreach (var target in list)
                    {
                        target.Approver = Helper.CurrentPrincipal.User.UserName;
                        target.ApprovedDate = DateTime.Now;
                        target.Comment = comment;
                        target.State = passed
                                                     ? (int)ProjectDataStateEnum.Confirmed
                                                     : (int)ProjectDataStateEnum.ConfirmationRejected;
                    }
                    context.SaveChanges();
                }
            }
        }


        internal static void ExecuteSign(Guid[] labours, bool passed)
        {
            if (null != labours && labours.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectLabour.Where(item => labours.Contains(item.LabourID)).ToList();

                    foreach (var target in list)
                    {
                        target.Signer = Helper.CurrentPrincipal.User.UserName;
                        target.SignedDate = DateTime.Now;
                        target.State = passed
                                                     ? (int)ProjectDataStateEnum.Signed
                                                     : (int)ProjectDataStateEnum.SignRejected;
                    }
                    context.SaveChanges();
                }
            }
        }
    }
}